#!/usr/bin/env ruby

# frozen_string_literal: true

require "bundler/inline"
require "psych"

gemfile do
  source "https://rubygems.org"
  gem "szczupac", ">= 0.4.0"
end

class CI
  RUBY_VERSIONS = [MRI_RUBY = [RUBY_3_4 = "ruby-3.4", RUBY_3_3 = "ruby-3.3", RUBY_3_2 = "ruby-3.2"]].flatten

  DATA_TYPES = [DATA_TEXT = "text", DATA_BINARY = "binary", DATA_JSON = "json", DATA_JSONB = "jsonb"]

  DATA_TYPES_IN_AR = [DATA_BINARY, DATA_TYPES.drop(2)].flatten
  DATA_TYPES_IN_SEQUEL = [DATA_TEXT, DATA_TYPES.drop(2)].flatten

  DATABASE_URLS = [
    SQLITE = "sqlite:db.sqlite3",
    SQLITE3 = "sqlite3:db.sqlite3",
    POSTGRES = [
      POSTGRES_17 = "postgres://postgres:secret@localhost:10017/rails_event_store",
      POSTGRES_13 = "postgres://postgres:secret@localhost:10013/rails_event_store",
    ],
    MYSQL = [
      MYSQL_8_4 = "mysql2://root:secret@127.0.0.1:10084/rails_event_store",
      MYSQL_8_0 = "mysql2://root:secret@127.0.0.1:10080/rails_event_store",
    ],
  ].flatten

  GEMFILE = "Gemfile"

  RAILS_GEMFILES = [GEMFILE_RAILS_7_2 = "Gemfile.rails_7_2", GEMFILE_RAILS_7_1 = "Gemfile.rails_7_1"].flatten

  AS_GEMFILES = [GEMFILE_AS_7_2 = "Gemfile.activesupport_7_2", GEMFILE_AS_7_1 = "Gemfile.activesupport_7_1"]

  AR_GEMFILES = [GEMFILE_AR_7_2 = "Gemfile.activerecord_7_2", GEMFILE_AR_7_1 = "Gemfile.activerecord_7_1"]

  SIDEKIQ_GEMFILES = [GEMFILE_SIDEKIQ_6_5 = "Gemfile.sidekiq_6_5"]

  def workflows
    [
      release_test("aggregate_root"),
      release_mutate("aggregate_root"),
      release_coverage("aggregate_root"),
      release_test("ruby_event_store"),
      release_mutate("ruby_event_store"),
      release_coverage("ruby_event_store"),
      release_test("ruby_event_store-rspec"),
      release_mutate("ruby_event_store-rspec"),
      release_coverage("ruby_event_store-rspec"),
      release_test(
        "ruby_event_store-browser",
        steps: [checkout, verify_lockfile, setup_ruby, setup_node, cache_elm, make("install-npm test")],
        matrix: generate(ruby_version(RUBY_VERSIONS), bundle_gemfile(GEMFILE, "Gemfile.rack_2_0")),
      ),
      release_mutate("ruby_event_store-browser"),
      release_coverage("ruby_event_store-browser"),
      release_test(
        "rails_event_store",
        matrix:
          join(
            generate(ruby_version(RUBY_VERSIONS), bundle_gemfile(GEMFILE)),
            generate(ruby_version(RUBY_3_4), bundle_gemfile(RAILS_GEMFILES.take(1))),
            generate(ruby_version(RUBY_3_3), bundle_gemfile(RAILS_GEMFILES.drop(1))),
          ),
      ),
      release_mutate("rails_event_store"),
      release_coverage("rails_event_store"),
      release_test(
        "ruby_event_store-active_record",
        services: [postgres_13, postgres_17, mysql_8_0, mysql_8_4],
        matrix:
          join(
            generate(
              generate(ruby_version(RUBY_VERSIONS), bundle_gemfile(GEMFILE)),
              join(
                generate(database_url(SQLITE3), data_type(DATA_TYPES_IN_AR.take(1))),
                generate(database_url(POSTGRES), data_type(DATA_TYPES_IN_AR)),
                generate(database_url(MYSQL), data_type(DATA_TYPES_IN_AR.take(2))),
              ),
            ),
            generate(
              generate(ruby_version(RUBY_3_4), bundle_gemfile(AR_GEMFILES.take(1))),
              join(
                generate(database_url(SQLITE3), data_type(DATA_TYPES_IN_AR.take(1))),
                generate(database_url(POSTGRES), data_type(DATA_TYPES_IN_AR)),
                generate(database_url(MYSQL), data_type(DATA_TYPES_IN_AR.take(2))),
              ),
            ),
            generate(
              generate(ruby_version(RUBY_3_3), bundle_gemfile(AR_GEMFILES.drop(1))),
              join(
                generate(database_url(SQLITE3), data_type(DATA_TYPES_IN_AR.take(1))),
                generate(database_url(POSTGRES), data_type(DATA_TYPES_IN_AR)),
                generate(database_url(MYSQL), data_type(DATA_TYPES_IN_AR.take(2))),
              ),
            ),
          ),
      ),
      release_mutate("ruby_event_store-active_record"),
      release_coverage("ruby_event_store-active_record"),
      contrib_test(
        "ruby_event_store-flipper",
        matrix:
          join(
            generate(ruby_version(MRI_RUBY), bundle_gemfile(GEMFILE)),
            generate(ruby_version(RUBY_3_4), bundle_gemfile(AS_GEMFILES.take(1))),
            generate(ruby_version(RUBY_3_3), bundle_gemfile(AS_GEMFILES.drop(1))),
          ),
      ),
      contrib_mutate("ruby_event_store-flipper"),
      contrib_coverage("ruby_event_store-flipper"),
      contrib_test("ruby_event_store-newrelic"),
      contrib_mutate("ruby_event_store-newrelic"),
      contrib_coverage("ruby_event_store-newrelic"),
      contrib_test(
        "ruby_event_store-outbox",
        services: [mysql_8_0, mysql_8_4],
        matrix:
          join(
            generate(
              ruby_version(MRI_RUBY),
              bundle_gemfile(GEMFILE, SIDEKIQ_GEMFILES),
              database_url(SQLITE3, MYSQL_8_0, MYSQL_8_4),
            ),
            generate(
              ruby_version(RUBY_3_4),
              bundle_gemfile(RAILS_GEMFILES.take(1)),
              database_url(SQLITE3, MYSQL_8_0, MYSQL_8_4),
            ),
            generate(
              ruby_version(RUBY_3_3),
              bundle_gemfile(RAILS_GEMFILES.drop(1)),
              database_url(SQLITE3, MYSQL_8_0, MYSQL_8_4),
            ),
          ),
        steps: [checkout, setup_nix, setup_cachix, verify_lockfile, setup_ruby, make_nix_shell("test")],
      ),
      contrib_mutate(
        "ruby_event_store-outbox",
        steps: [
          checkout(depth: 0),
          setup_nix,
          setup_cachix,
          verify_lockfile,
          setup_ruby,
          make_nix_shell("mutate-changes"),
        ],
      ),
      contrib_coverage(
        "ruby_event_store-outbox",
        steps: [checkout, setup_nix, setup_cachix, verify_lockfile, setup_ruby, make_nix_shell("mutate")],
      ),
      contrib_test("ruby_event_store-profiler"),
      contrib_mutate("ruby_event_store-profiler"),
      contrib_coverage("ruby_event_store-profiler"),
      contrib_test(
        "ruby_event_store-protobuf",
        matrix:
          generate(ruby_version(MRI_RUBY - [RUBY_3_4]), bundle_gemfile(GEMFILE, RAILS_GEMFILES), database_url(SQLITE3)),
      ),
      contrib_mutate(
        "ruby_event_store-protobuf",
        matrix: generate(ruby_version(MRI_RUBY - [RUBY_3_4]), bundle_gemfile(GEMFILE)),
      ),
      contrib_coverage(
        "ruby_event_store-protobuf",
        matrix: generate(ruby_version(MRI_RUBY - [RUBY_3_4]), bundle_gemfile(GEMFILE)),
      ),
      contrib_test(
        "ruby_event_store-rom",
        services: [postgres_13, postgres_17, mysql_8_0, mysql_8_4],
        matrix:
          join(
            generate(
              ruby_version(MRI_RUBY),
              bundle_gemfile(GEMFILE),
              database_url(SQLITE),
              data_type(DATA_TYPES_IN_SEQUEL.take(1)),
            ),
            generate(
              ruby_version(MRI_RUBY.take(1)),
              bundle_gemfile(GEMFILE),
              database_url(POSTGRES),
              data_type(DATA_TYPES_IN_SEQUEL),
            ),
            generate(
              ruby_version(MRI_RUBY.take(1)),
              bundle_gemfile(GEMFILE),
              database_url(MYSQL),
              data_type(DATA_TYPES_IN_SEQUEL.take(1)),
            ),
          ),
      ),
      contrib_mutate("ruby_event_store-rom"),
      contrib_coverage("ruby_event_store-rom"),
      contrib_test(
        "ruby_event_store-sequel",
        services: [postgres_13, postgres_17, mysql_8_0, mysql_8_4],
        matrix:
          join(
            generate(
              ruby_version(MRI_RUBY),
              bundle_gemfile(GEMFILE),
              database_url(SQLITE),
              data_type(DATA_TYPES_IN_SEQUEL.take(1)),
            ),
            generate(
              ruby_version(MRI_RUBY.take(1)),
              bundle_gemfile(GEMFILE),
              database_url(POSTGRES),
              data_type(DATA_TYPES_IN_SEQUEL),
            ),
            generate(
              ruby_version(MRI_RUBY.take(1)),
              bundle_gemfile(GEMFILE),
              database_url(MYSQL),
              data_type(DATA_TYPES_IN_SEQUEL.take(1)),
            ),
          ),
      ),
      contrib_mutate("ruby_event_store-sequel"),
      contrib_coverage("ruby_event_store-sequel"),
      contrib_test(
        "ruby_event_store-sidekiq_scheduler",
        matrix: generate(ruby_version(MRI_RUBY), bundle_gemfile(GEMFILE, SIDEKIQ_GEMFILES)),
        steps: [checkout, setup_nix, setup_cachix, verify_lockfile, setup_ruby, make_nix_shell("test")],
      ),
      contrib_mutate(
        "ruby_event_store-sidekiq_scheduler",
        steps: [
          checkout(depth: 0),
          setup_nix,
          setup_cachix,
          verify_lockfile,
          setup_ruby,
          make_nix_shell("mutate-changes"),
        ],
      ),
      contrib_coverage(
        "ruby_event_store-sidekiq_scheduler",
        steps: [checkout, setup_nix, setup_cachix, verify_lockfile, setup_ruby, make_nix_shell("mutate")],
      ),
      contrib_test("ruby_event_store-transformations"),
      contrib_mutate("ruby_event_store-transformations"),
      contrib_coverage("ruby_event_store-transformations"),
      contrib_test("minitest-ruby_event_store"),
      contrib_mutate("minitest-ruby_event_store"),
      contrib_coverage("minitest-ruby_event_store"),
      contrib_test("dres_client", triggers: dres_triggers("dres_client_test")),
      contrib_test(
        "dres_rails",
        services: [postgres_13, postgres_17],
        matrix:
          generate(
            ruby_version(MRI_RUBY),
            bundle_gemfile(GEMFILE),
            database_url(POSTGRES),
            data_type(DATA_TYPES_IN_AR.reject { |t| t == DATA_JSONB }),
          ),
        triggers: dres_triggers("dres_rails_test"),
      ),
      assets("ruby_event_store-browser"),
    ]
  end

  module Actions
    def checkout(depth: 1)
      { "uses" => "actions/checkout@v4", "with" => { "fetch-depth" => depth } }
    end

    def verify_lockfile
      { "run" => "test -e ${{ env.BUNDLE_GEMFILE }}.lock", "working-directory" => "${{ env.WORKING_DIRECTORY }}" }
    end

    def setup_ruby
      {
        "uses" => "ruby/setup-ruby@v1",
        "with" => {
          "ruby-version" => "${{ env.RUBY_VERSION }}",
          "bundler-cache" => true,
          "working-directory" => "${{ env.WORKING_DIRECTORY }}",
        },
      }
    end

    def setup_node
      {
        "uses" => "actions/setup-node@v4",
        "with" => {
          "node-version" => 20,
          "cache" => "npm",
          "cache-dependency-path" => "${{ env.WORKING_DIRECTORY }}/elm/package-lock.json",
        },
      }
    end

    def cache_elm
      {
        "uses" => "actions/cache@v4",
        "with" => {
          "path" => "~/.elm",
          "key" => "elm-${{ hashFiles(format('{0}/elm/elm.json', env.WORKING_DIRECTORY)) }}",
        },
      }
    end

    def setup_nix
      { "uses" => "cachix/install-nix-action@v25", "with" => { "nix_path" => "nixpkgs=channel:nixos-unstable" } }
    end

    def setup_cachix
      {
        "uses" => "cachix/cachix-action@v14",
        "with" => {
          "name" => "railseventstore",
          "authToken" => "${{ secrets.CACHIX_AUTH_TOKEN }}",
        },
      }
    end

    def make_nix_shell(target, imports: ["redis.nix"])
      { "run" => <<~SHELL, "working-directory" => "${{ env.WORKING_DIRECTORY }}" }
        nix-shell --run "make #{target}" -E"
          with import <nixpkgs> { };
          mkShell {
            inputsFrom = [
              #{imports.map { |i| "(import ../../support/nix/#{i})" }.join("\n")}
            ];
          }
        "
      SHELL
    end

    def make(target)
      body = {
        "run" => "make #{target}",
        "working-directory" => "${{ env.WORKING_DIRECTORY }}",
        "env" => {
          "RUBYOPT" => "--enable-frozen-string-literal",
        },
      }
      body
    end

    def upload_artifact(name)
      {
        "uses" => "actions/upload-artifact@v4",
        "with" => {
          "name" => name,
          "path" => "${{ env.WORKING_DIRECTORY }}/public/#{name}",
        },
      }
    end

    def configure_aws_credentials
      {
        "uses" => "aws-actions/configure-aws-credentials@v4",
        "with" => {
          "aws-access-key-id" => "${{ secrets.AWS_ACCESS_KEY_ID }}",
          "aws-secret-access-key" => "${{ secrets.AWS_SECRET_ACCESS_KEY }}",
          "aws-region" => "eu-central-1",
        },
      }
    end

    def set_short_sha_env
      { "run" => "echo \"SHORT_SHA=$(git rev-parse --short=12 HEAD)\" >> $GITHUB_ENV" }
    end

    def aws_s3_sync
      { "run" => "aws s3 sync ${{ env.WORKING_DIRECTORY }}/public s3://ruby-event-store-assets/${{ env.SHORT_SHA }}" }
    end
  end
  include Actions

  module Triggers
    def manual_trigger
      { "workflow_dispatch" => nil }
    end

    def api_trigger
      { "repository_dispatch" => { "types" => ["script"] } }
    end

    def push_trigger(paths = [])
      return { "push" => nil } if paths.empty?
      { "push" => { "branches" => ["master"], "paths" => paths } }
    end

    def pr_trigger(paths)
      { "pull_request" => { "paths" => paths } }
    end

    def scheduled_trigger
      { "schedule" => [{ "cron" => "0 17 * * *" }] }
    end

    def release_triggers(workflow_name)
      paths = release_paths(workflow_name)
      [manual_trigger, api_trigger, push_trigger(paths.dup), pr_trigger(paths.dup)]
    end

    def contrib_triggers(workflow_name, working_directory)
      paths = contrib_paths(workflow_name, working_directory)
      [manual_trigger, api_trigger, push_trigger(paths.dup), pr_trigger(paths.dup)]
    end

    def coverage_triggers(workflow_name, working_directory)
      paths = coverage_paths(workflow_name, working_directory)
      [manual_trigger, api_trigger, push_trigger(paths.dup), pr_trigger(paths.dup), scheduled_trigger]
    end

    def dres_triggers(workflow_name)
      paths = dres_paths(workflow_name)
      [manual_trigger, api_trigger, push_trigger(paths.dup), pr_trigger(paths.dup)]
    end

    def release_paths(workflow_name)
      [
        %w[
          aggregate_root
          rails_event_store
          ruby_event_store
          ruby_event_store-active_record
          ruby_event_store-browser
          ruby_event_store-rspec
        ].map { |name| "#{name}/**" },
        workflow_paths(workflow_name),
        support_paths,
      ].reduce(&:concat).uniq
    end

    def contrib_paths(workflow_name, working_directory)
      [own_paths(working_directory), workflow_paths(workflow_name), support_paths].reduce(&:concat).uniq
    end

    def coverage_paths(workflow_name, working_directory)
      [[working_directory].map { |wd| "#{wd}/Gemfile.lock" }, workflow_paths(workflow_name), support_paths].reduce(
        &:concat
      ).uniq
    end

    def dres_paths(workflow_name)
      [
        %w[dres_client dres_rails].map { |name| "contrib/#{name}/**" },
        workflow_paths(workflow_name),
        support_paths,
      ].reduce(&:concat).uniq
    end

    def own_paths(working_directory)
      %W[#{working_directory}/**]
    end

    def workflow_paths(workflow_name)
      %W[.github/workflows/#{workflow_name}.yml]
    end

    def support_paths
      %w[support/** !support/bundler/** !support/ci/**]
    end
  end
  include Triggers

  module Services
    def postgres_13
      {
        "postgres_13" => {
          "image" => "postgres:13",
          "env" => {
            "POSTGRES_DB" => "rails_event_store",
            "POSTGRES_PASSWORD" => "secret",
          },
          "ports" => ["10013:5432"],
          "options" => "--health-cmd \"pg_isready\" --health-interval 10s --health-timeout 5s --health-retries 5",
        },
      }
    end

    def postgres_17
      {
        "postgres_17" => {
          "image" => "postgres:17",
          "env" => {
            "POSTGRES_DB" => "rails_event_store",
            "POSTGRES_PASSWORD" => "secret",
          },
          "ports" => ["10017:5432"],
          "options" => "--health-cmd \"pg_isready\" --health-interval 10s --health-timeout 5s --health-retries 5",
        },
      }
    end

    def mysql_8_0
      {
        "mysql_8" => {
          "image" => "mysql:8.0",
          "env" => {
            "MYSQL_DATABASE" => "rails_event_store",
            "MYSQL_ROOT_PASSWORD" => "secret",
          },
          "ports" => ["10080:3306"],
          "options" => "--health-cmd \"mysqladmin ping\" --health-interval 10s --health-timeout 5s --health-retries 5",
        },
      }
    end

    def mysql_8_4
      {
        "mysql_8_4" => {
          "image" => "mysql:8.4",
          "env" => {
            "MYSQL_DATABASE" => "rails_event_store",
            "MYSQL_ROOT_PASSWORD" => "secret",
          },
          "ports" => ["10084:3306"],
          "options" => "--health-cmd \"mysqladmin ping\" --health-interval 10s --health-timeout 5s --health-retries 5",
        },
      }
    end
  end
  include Services

  module Matrix
    def generate(*axes)
      Szczupac.generate(*axes)
    end

    def axis(name, *items)
      Szczupac.axis(name, Array(items.flatten))
    end

    def join(*axes)
      axes.flatten.uniq
    end

    def ruby_version(*ruby_version)
      axis("ruby_version", *ruby_version)
    end

    def bundle_gemfile(*gemfile)
      axis("bundle_gemfile", *gemfile)
    end

    def database_url(*database_url)
      axis("database_url", *database_url)
    end

    def data_type(*data_type)
      axis("data_type", *data_type)
    end
  end
  include Matrix

  module Workflows
    class Workflow
      include Triggers
      include Matrix
      include Actions

      def initialize(
        gem,
        job_name: "test",
        name: "#{gem}_#{job_name}",
        working_directory: gem,
        matrix: generate(ruby_version(RUBY_VERSIONS), bundle_gemfile(GEMFILE)),
        steps: [checkout, verify_lockfile, setup_ruby, make("test")],
        services: [],
        triggers: release_triggers(name),
        runs_on: "ubuntu-latest",
        env: {}
      )
        @gem = gem
        @job_name = job_name
        @name = name
        @working_directory = working_directory
        @matrix = matrix
        @steps = steps
        @services = services
        @triggers = triggers
        @runs_on = runs_on
        @env = env
      end

      def to_h
        { "name" => name, "on" => triggers.reduce(&:merge), "jobs" => { job_name => job } }
      end

      attr_reader :gem, :job_name, :name, :working_directory, :matrix, :steps, :services, :triggers, :runs_on, :env

      private

      def job
        {
          "runs-on" => runs_on,
          "timeout-minutes" => 120,
          "env" => { "WORKING_DIRECTORY" => working_directory }.merge(mk_env(matrix)).merge(env),
          "services" => services.reduce(&:merge),
          "strategy" => {
            "fail-fast" => false,
            "matrix" => {
              "include" => matrix,
            },
          },
          "steps" => steps,
        }.reject { |k, _| k == "services" && services.empty? }.reject { |k, _| k == "strategy" && matrix.empty? }
      end

      def mk_env(matrix)
        matrix
          .take(1)
          .reduce({}) do |acc, matrix_item|
            matrix_item.reduce(acc) { |acc, (key, _)| acc.merge(key.upcase => "${{ matrix.#{key} }}") }
          end
      end
    end

    def release_test(name, **)
      Workflow.new(name, **)
    end

    def contrib_test(
      name,
      working_directory: "contrib/#{name}",
      matrix: generate(ruby_version(MRI_RUBY), bundle_gemfile(GEMFILE)),
      **
    )
      Workflow.new(
        name,
        working_directory: working_directory,
        matrix: matrix,
        triggers: contrib_triggers("#{name}_test", working_directory),
        **,
      )
    end

    def release_mutate(
      name,
      matrix: generate(ruby_version(MRI_RUBY.take(1)), bundle_gemfile(GEMFILE)),
      steps: [checkout(depth: 0), verify_lockfile, setup_ruby, make("mutate-changes")],
      **
    )
      Workflow.new(
        name,
        job_name: "mutate",
        matrix: matrix,
        steps: steps,
        runs_on: "macos-14",
        env: {
          "BUNDLE_WITHOUT" => "database",
          "SINCE_SHA" => "${{ github.event.pull_request.base.sha || 'HEAD~1' }}",
        },
        **,
      )
    end

    def contrib_mutate(
      name,
      working_directory: "contrib/#{name}",
      matrix: generate(ruby_version(MRI_RUBY.take(1)), bundle_gemfile(GEMFILE)),
      steps: [checkout(depth: 0), verify_lockfile, setup_ruby, make("mutate-changes")],
      **
    )
      Workflow.new(
        name,
        job_name: "mutate",
        working_directory: working_directory,
        matrix: matrix,
        steps: steps,
        triggers: contrib_triggers("#{name}_mutate", working_directory),
        runs_on: "macos-14",
        env: {
          "BUNDLE_WITHOUT" => "database",
          "SINCE_SHA" => "${{ github.event.pull_request.base.sha || 'HEAD~1' }}",
        },
        **,
      )
    end

    def release_coverage(
      name,
      matrix: generate(ruby_version(MRI_RUBY.take(1)), bundle_gemfile(GEMFILE)),
      steps: [checkout, verify_lockfile, setup_ruby, make("mutate")],
      **
    )
      Workflow.new(
        name,
        job_name: "coverage",
        matrix: matrix,
        steps: steps,
        triggers: coverage_triggers("#{name}_coverage", name),
        runs_on: "macos-14",
        env: {
          "BUNDLE_WITHOUT" => "database",
        },
        **,
      )
    end

    def contrib_coverage(
      name,
      working_directory: "contrib/#{name}",
      matrix: generate(ruby_version(MRI_RUBY.take(1)), bundle_gemfile(GEMFILE)),
      steps: [checkout, verify_lockfile, setup_ruby, make("mutate")],
      **
    )
      Workflow.new(
        name,
        job_name: "coverage",
        working_directory: working_directory,
        matrix: matrix,
        steps: steps,
        triggers: coverage_triggers("#{name}_coverage", working_directory),
        runs_on: "macos-14",
        env: {
          "BUNDLE_WITHOUT" => "database",
        },
        **,
      )
    end

    def assets(name)
      Workflow.new(
        name,
        job_name: "assets",
        matrix: [],
        steps: [
          checkout,
          setup_node,
          cache_elm,
          make("install-npm"),
          make("build-npm"),
          upload_artifact("ruby_event_store_browser.js"),
          upload_artifact("ruby_event_store_browser.css"),
          configure_aws_credentials,
          set_short_sha_env,
          aws_s3_sync,
        ],
        triggers: [manual_trigger, api_trigger, push_trigger],
      )
    end
  end
  include Workflows

  def as_github_actions
    workflows.each do |workflow|
      filename = "#{workflow.name}.yml"
      File.write(File.join(workflows_root, filename), as_yaml(workflow.to_h))
      puts "writing #{filename}"
    end
  end

  def as_yaml(content)
    Psych.safe_dump(content, line_width: 120).lines.drop(1).join.strip.gsub(/'on':\n/, "on:\n")
  end

  def initialize(workflows_root, template_root)
    @workflows_root = workflows_root
    @template_root = template_root
  end

  attr_reader :workflows_root, :template_root
end

CI.new(File.join(__dir__, "../../.github/workflows/"), __dir__).as_github_actions
